<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Layout management in Qt4</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Qt4, tutorial, widgets, layout, C++, programming, GUI, multiplatform">
<meta name="description" content="This chapter of the Qt4 tutorial presents
layout management of widgets.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-5536206-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Layout management in Qt4</h1>

<p>
In this part of the Qt4 programming tutorial, we will talk about the layout 
management of widgets. 
</p>

<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* NewSquare */
google_ad_slot = "0364418177";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script>

<p>
A typical application consists of various widgets. Those widgets are placed 
inside layouts. A programmer must manage the layout of the application. In Qt4 
programming library we have two options.
</p>

<ul>
<li>absolute positioning</li>
<li>layouts</li>
</ul>


<h2>Absolute Positioning</h2>

<p>
The programmer specifies the position and the size of each widget in pixels. 
When you use absolute positioning, you have to understand several things. 
</p>

<ul>
<li>the size and the position of a widget do not change, if you resize a window</li>
<li>applications look different (often crappy) on various platforms</li>
<li>changing fonts in your application might spoil the layout</li>
<li>if you decide to change your layout, you must completely redo your layout, 
which is tedious and time consuming</li>
</ul>

<p>
There might be situations, where we can possibly use absolute positioning. 
For example, this tutorial. We do not want to make the examples too difficult, 
so we often use absolute positioning to explain a topic. But mostly, in real 
world programs, programmers use layouts.
</p>

<div class="codehead">absolute.cpp</div>
<pre class="code">
#include &lt;QApplication&gt;
#include &lt;QDesktopWidget&gt;
#include &lt;QTextEdit&gt;


class Absolute : public QWidget
{
 public:
     Absolute(QWidget *parent = 0);
};


Absolute::Absolute(QWidget *parent)
    : QWidget(parent)
{
  QTextEdit *edit = new QTextEdit(this);
  edit->setGeometry(5, 5, 200, 150);
}

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);

  Absolute window;

  window.setWindowTitle("Absolute");
  window.show();

  return app.exec();
}
</pre>

<p>
The <code>setGeometry()</code> method is used to position the widget on the
window in absolute coordinates. 
</p>

<pre class="explanation">
QTextEdit *edit = new QTextEdit(this);
edit->setGeometry(5, 5, 200, 150);
</pre>

<p>
We create a <code>QTextEdit</code> widget and manually position it. The 
<code>setGeometry()</code> method does two things. It positions the widget to 
absolute coordinates and resizes the widget.  
</p>

<img src="/img/gui/qt4/absolute1.png" alt="Before resizement"> 
<div class="figure">
Figure: before resizement
</div>

<br>
<img src="/img/gui/qt4/absolute2.png" alt="After resizement">
<div class="figure">
Figure: after resizement
</div>


<h2>QVBoxLayout</h2>

<p>
The <code>QVBoxLayout</code> class lines up widgets vertically. The widgets are
added to the layout using the <code>addWidget()</code> method.
</p>

<div class="codehead">verticalbox.h</div>
<pre class="code">
#pragma once

#include &lt;QWidget&gt;

class VerticalBox : public QWidget
{
  public:
    VerticalBox(QWidget *parent = 0);

};
</pre>

<p>
The header file. 
</p>

<div class="codehead">verticalbox.cpp</div>
<pre class="code">
#include &lt;QVBoxLayout&gt;
#include &lt;QPushButton&gt;
#include "verticalbox.h"

VerticalBox::VerticalBox(QWidget *parent)
    : QWidget(parent)
{
  QVBoxLayout *vbox = new QVBoxLayout(this);
  vbox->setSpacing(1);

  QPushButton *settings = new QPushButton("Settings", this);
  settings->setSizePolicy(QSizePolicy::Expanding, 
      QSizePolicy::Expanding);
  QPushButton *accounts = new QPushButton("Accounts", this);
  accounts->setSizePolicy(QSizePolicy::Expanding, 
      QSizePolicy::Expanding);
  QPushButton *loans = new QPushButton("Loans", this);
  loans->setSizePolicy(QSizePolicy::Expanding, 
      QSizePolicy::Expanding);
  QPushButton *cash = new QPushButton("Cash", this);
  cash->setSizePolicy(QSizePolicy::Expanding, 
      QSizePolicy::Expanding);
  QPushButton *debts = new QPushButton("Debts", this);
  debts->setSizePolicy(QSizePolicy::Expanding, 
      QSizePolicy::Expanding);

  vbox->addWidget(settings);
  vbox->addWidget(accounts);
  vbox->addWidget(loans);
  vbox->addWidget(cash);
  vbox->addWidget(debts);

  setLayout(vbox);
}
</pre>

<p>
In our example, we have one vertical layout manager. We put five buttons 
into it. We make all buttons expandable in both directions. 
</p>

<pre class="explanation">
QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->setSpacing(1);
</pre>

<p>
We create the <code>QVBoxLayout</code> and set 1px spacing among 
child widgets. 
</p>

<pre class="explanation">
QPushButton *settings = new QPushButton("Settings", this);
settings->setSizePolicy(QSizePolicy::Expanding, 
   QSizePolicy::Expanding);
</pre>

<p>
We create a button and set a size policy for it. The child widgets are managed 
by the layout manager. By default, the button is expanded horizontally and has a 
fixed size vertically. If we want to change it, we set a new size policy. In our 
case, the button is expandable into both directions. 
</p>

<pre class="explanation">
vbox->addWidget(settings);
vbox->addWidget(accounts);
vbox->addWidget(loans);
vbox->addWidget(cash);
vbox->addWidget(debts);
</pre>

<p>
We add the child widgets to the layout manager. 
</p>

<pre class="explanation">
setLayout(vbox);
</pre>

<p>
We set the <code>QVBoxLayout</code> manager for the window. 
</p>

<div class="codehead">main.cpp</div>
<pre class="code">
#include &lt;QApplication&gt;
#include "verticalbox.h"

int main(int argc, char *argv[])
{
  QApplication app(argc, argv); 

  VerticalBox window;

  window.resize(240, 230);
  window.move(300, 300);
  window.setWindowTitle("VerticalBox");
  window.show();
  
  return app.exec();
}
</pre>

<p>
Main file. 
</p>

<img src="/img/gui/qt4/verticalbox.png" alt="QVBoxLayout">
<div class="figure">
Figure: QVBoxLayout
</div>


<h2>Buttons</h2>

<p>
In the following example, we display two buttons on the client area of the 
window. They will be positioned in the right bottom corner of the window. 
</p>

<div class="codehead">buttons.h</div>
<pre class="code">
#pragma once

#include &lt;QWidget&gt;
#include &lt;QPushButton&gt;

class Buttons : public QWidget
{
  public:
    Buttons(QWidget *parent = 0);

  private:
    QPushButton *ok;
    QPushButton *apply;

};
</pre>

<p>
Header file. 
</p>

<div class="codehead">buttons.cpp</div>
<pre class="code">
#include &lt;QVBoxLayout&gt;
#include &lt;QHBoxLayout&gt;
#include "buttons.h"

Buttons::Buttons(QWidget *parent)
    : QWidget(parent)
{
  QVBoxLayout *vbox = new QVBoxLayout(this);
  QHBoxLayout *hbox = new QHBoxLayout();

  ok = new QPushButton("OK", this);
  apply = new QPushButton("Apply", this);

  hbox->addWidget(ok, 1, Qt::AlignRight);
  hbox->addWidget(apply, 0, Qt::AlignRight);

  vbox->addStretch(1);
  vbox->addLayout(hbox);
}
</pre>

<p>
Say we wanted to have two buttons in the right bottom corner of the window. 
</p>

<pre class="explanation">
QVBoxLayout *vbox = new QVBoxLayout(this);
QHBoxLayout *hbox = new QHBoxLayout();
</pre>

<p>
We create two box layout managers. One vertical and one horizontal 
box layout manager. 
</p>

<pre class="explanation">
ok = new QPushButton("OK", this);
apply = new QPushButton("Apply", this);
</pre>

<p>
We create two buttons. 
</p>

<pre class="explanation">
hbox->addWidget(ok, 1, Qt::AlignRight);
hbox->addWidget(apply, 0, Qt::AlignRight);
</pre>

<p>
The buttons are placed inside the horizontal layout manager. These buttons are 
right aligned. We use the <code>addWidget()</code> method. The first parameter 
is the child widget. The second parameter is the stretch factor and the last 
parameter is alignment. By setting the stretch factor to 1 for the ok button, we 
give it space from the left side to the right side of the window. The widget 
does not expand to all space alloted to it. Finally, the 
<code>Qt::AlignRight</code> constant aligns the widget to the right of the 
allotted space. We also right aligned the apply button, but it was not 
necessary. The ok button already pushes the apply button to the right. 
</p>

<pre class="explanation">
vbox->addStretch(1);
vbox->addLayout(hbox);
</pre>

<p>
We put an empty, expandable space into the vertical box by calling the 
<code>addStretch()</code> method. Then we add the horizontal box layout to the 
vertical box layout. 
</p>

<div class="codehead">main.cpp</div>
<pre class="code">
#include &lt;QApplication&gt;
#include "buttons.h"

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);  

  Buttons window;

  window.resize(290, 170);
  window.move(300, 300);  
  window.setWindowTitle("Buttons");
  window.show();
  
  return app.exec();
}
</pre>


<p>
Main file. 
</p>

<img src="/img/gui/qt4/buttons.png" alt="Buttons">
<div class="figure">
Figure: Buttons
</div>


<h2>Nesting layouts</h2>

<p>
The idea of the following example is to show that layout managers can be 
combined. By combination of even simple layouts we can create sophisticated 
dialogs or windows. To nest layouts, we utilize the <code>addLayout()</code>
method.
</p>


<div class="codehead">layouts.h</div>
<pre class="code">
#pragma once

#include &lt;QWidget&gt;

class Layouts : public QWidget
{
  public:
    Layouts(QWidget *parent = 0);

};
</pre>

<p>
Header file. 
</p>

<div class="codehead">layouts.cpp</div>
<pre class="code">
#include &lt;QVBoxLayout&gt;
#include &lt;QPushButton&gt;
#include &lt;QListWidget&gt;
#include "layouts.h"

Layouts::Layouts(QWidget *parent)
    : QWidget(parent)
{

  QVBoxLayout *vbox = new QVBoxLayout();
  QHBoxLayout *hbox = new QHBoxLayout(this);

  QListWidget *lw = new QListWidget(this);
  lw->addItem("The Omen"); 
  lw->addItem("The Exorcist");
  lw->addItem("Notes on a scandal");
  lw->addItem("Fargo");
  lw->addItem("Capote");

  QPushButton *add = new QPushButton("Add", this);
  QPushButton *rename = new QPushButton("Rename", this);
  QPushButton *remove = new QPushButton("Remove", this);
  QPushButton *removeall = new QPushButton("Remove All", this);

  vbox->setSpacing(3);
  vbox->addStretch(1);
  vbox->addWidget(add);
  vbox->addWidget(rename);
  vbox->addWidget(remove);
  vbox->addWidget(removeall);
  vbox->addStretch(1);

  hbox->addWidget(lw);
  hbox->addSpacing(15);
  hbox->addLayout(vbox);

  setLayout(hbox);
}
</pre>

<p>
In the example, we create a window that consists of four buttons and one list 
widget. The buttons are grouped in a vertical column and placed to the right of 
the list widget. If we resize the window, the list widget is being resized as 
well.
</p>

<pre class="explanation">
QVBoxLayout *vbox = new QVBoxLayout();
</pre>

<p>
The <code>QVBoxLayout</code> will be the column for the buttons. 
</p>

<pre class="explanation">
QHBoxLayout *hbox = new QHBoxLayout(this);
</pre>

<p>
The <code>QHBoxLayout</code> will be the base layout for our widgets. 
</p>

<pre class="explanation">
QListWidget *lw = new QListWidget(this);
lw->addItem("The Omen"); 
lw->addItem("The Exorcist");
lw->addItem("Notes on a scandal");
lw->addItem("Fargo");
lw->addItem("Capote");
</pre>

<p>
Here we create the list widget. 
</p>

<pre class="explanation">
QPushButton *add = new QPushButton("Add", this);
QPushButton *rename = new QPushButton("Rename", this);
QPushButton *remove = new QPushButton("Remove", this);
QPushButton *removeall = new QPushButton("Remove All", this);
</pre>

<p>
Here we create our four buttons. 
</p>

<pre class="explanation">
vbox->setSpacing(3);
vbox->addStretch(1);
vbox->addWidget(add);
vbox->addWidget(rename);
vbox->addWidget(remove);
vbox->addWidget(removeall);
vbox->addStretch(1);
</pre>

<p>
The vertical box with four buttons is created. We put some little space among 
our buttons. Notice that we add a stretch factor to the top and to the bottom of 
the vertical box. This way, the buttons are vertically centered. 
</p>

<pre class="explanation">
hbox->addWidget(lw);
hbox->addSpacing(15);
hbox->addLayout(vbox);
</pre>

<p>
The list widget and the vertical box of buttons are placed into the horizontal 
box layout. The <code>addLayout()</code> method is used to add a layout to 
another layout. 
</p>

<pre class="explanation">
setLayout(hbox);
</pre>

<p>
We set the base layout for the parent window. 
</p>

<div class="codehead">main.cpp</div>
<pre class="code">
#include &lt;QApplication&gt;
#include "layouts.h"

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);  
    
  Layouts window;
  
  window.move(300, 300);
  window.setWindowTitle("Layouts");
  window.show();

  return app.exec();
}
</pre>

<p>
Main file. 
</p>

<img src="/img/gui/qt4/nestedlayouts.png" alt="Layouts">
<div class="figure">
Figure: Layouts
</div>


<h2>QGridLayout</h2>


<p>
The <code>QGridLayout</code> places its widgets in a grid. It is a very 
sophisticated and powerful layout. Every programmer should be familiar with this 
layout. 
</p>

<div class="codehead">calculator.h</div>
<pre class="code">
#pragma once

#include &lt;QWidget&gt;

class Calculator : public QWidget
{
  public:
    Calculator(QWidget *parent = 0);

};
</pre>

<p>
Header file. 
</p>

<div class="codehead">calculator.cpp</div>
<pre class="code">
#include &lt;QPushButton&gt;
#include &lt;QGridLayout&gt;
#include "calculator.h"

Calculator::Calculator(QWidget *parent)
    : QWidget(parent)
{
  QGridLayout *grid = new QGridLayout(this);
  grid->setSpacing(2);

  QString values[16] = { "7", "8", "9", "/", 
    "4", "5", "6", "*",
    "1", "2", "3", "-",
    "0", ".", "=", "+"
  };

  int pos = 0;

  for (int i=0; i&lt;4; i++) {
    for (int j=0; j&lt;4; j++) {
      QPushButton *btn = new QPushButton(values[pos], this);
      btn->setFixedSize(40, 40);
      grid->addWidget(btn, i, j);
      pos++;
    }
  }

  setLayout(grid);
}
</pre>

<p>
We create the skeleton of a calculator. 
</p>

<pre class="explanation">
QGridLayout *grid = new QGridLayout(this);
grid->setSpacing(2);
</pre>

<p>
We create the grid layout and set 2px space among child widgets. 
</p>

<pre class="explanation">
QString values[16] = { "7", "8", "9", "/", 
  "4", "5", "6", "*",
  "1", "2", "3", "-",
  "0", ".", "=", "+"
};
</pre>

<p>
These are the characters that will be displayed on the buttons. 
</p>

<pre class="explanation">
for (int i=0; i&lt;4; i++) {
 for (int j=0; j&lt;4; j++) {
   QPushButton *btn = new QPushButton(values[pos], this);
   btn->setFixedSize(40, 40);
   grid->addWidget(btn, i, j);
   pos++;
 }
}
</pre>

<p>
We place 16 widgets into the grid layout. Each of the buttons will have a 
fixed size. 
</p>

<div class="codehead">main.cpp</div>
<pre class="code">
#include &lt;QApplication&gt;
#include "calculator.h"

int main(int argc, char *argv[])
{
  QApplication app(argc, argv); 

  Calculator window;

  window.move(300, 300);
  window.setWindowTitle("Calculator");
  window.show();

  return app.exec();
}
</pre>

<p>
Main file. 
</p>


<img src="/img/gui/qt4/calculator.png" alt="QGridLayout">
<div class="figure">
Figure: QGridLayout
</div>


<h2>More complicated layout</h2>

<p>
In the last example of this chapter, we create a more complicated window using 
the <code>QGridLayout</code> manager.
</p>


<div class="codehead">karenina.h</div>
<pre class="code">
#pragma once

#include &lt;QWidget&gt;

class Karenina : public QWidget
{
  public:
    Karenina(QWidget *parent = 0);

};
</pre>

<p>
Header file. 
</p>

<div class="codehead">karenina.cpp</div>
<pre class="code">
#include &lt;QGridLayout&gt;
#include &lt;QLabel&gt;
#include &lt;QLineEdit&gt;
#include &lt;QTextEdit&gt;
#include "karenina.h"

Karenina::Karenina(QWidget *parent)
    : QWidget(parent)
{
  QGridLayout *grid = new QGridLayout(this);
  grid->setSpacing(20);

  QLabel *title = new QLabel("Title", this);
  grid->addWidget(title, 0, 0, 1, 1);

  QLineEdit *edt1 = new QLineEdit(this);
  grid->addWidget(edt1, 0, 1, 1, 1);

  QLabel *author = new QLabel("Author", this);
  grid->addWidget(author, 1, 0, 1, 1);

  QLineEdit *edt2 = new QLineEdit(this);
  grid->addWidget(edt2, 1, 1, 1, 1);

  QLabel *review = new QLabel("Review", this);
  grid->addWidget(review, 2, 0, 1, 1);

  QTextEdit *te = new QTextEdit(this);
  grid->addWidget(te, 2, 1, 3, 1);

  setLayout(grid);
}
</pre>

<p>
The code creates a window, which could be used to enter a author, 
title and a review for a book. 
</p>

<pre class="explanation">
QGridLayout *grid = new QGridLayout(this);
grid->setSpacing(20);
</pre>

<p>
We create a grid layout and set some spacing. 
</p>

<pre class="explanation">
QLabel *title = new QLabel("Title", this);
grid->addWidget(title, 0, 0, 1, 1);
</pre>

<p>
These code lines create a label widget and place it into the grid layout. 
The <code>addWidget()</code> method has five parameters. The 
first parameter is the child widget. A label in our case. The next two 
parameters are the row and column in the grid, where we place the label. 
Finally, the last parameters are the rowspan and the colspan. These parameter 
specify, how many rows the current widget will span. 
In our case, the label will span only one column and one row. 
</p>

<pre class="explanation">
QTextEdit *te = new QTextEdit(this);
grid->addWidget(te, 2, 1, 3, 1);
</pre>

<p>
The <code>QTextEdit</code> widget is placed into the third row, second column.
It spans three rows and one column.
</p>


<div class="codehead">main.cpp</div>
<pre class="code">
#include &lt;QApplication&gt;
#include "karenina.h"

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);  

  Karenina window;

  window.move(300, 300);
  window.setWindowTitle("Anna Karenina");
  window.show();

  return app.exec();
}
</pre>

<p>
Main file. 
</p>


<img src="/img/gui/qt4/karenina.png" alt="Karenina">
<div class="figure">
Figure: Karenina
</div>


<p>
This part of the Qt4 tutorial was dedicated to layout management.
</p>


<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified October 16, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>


